package com.vne.skyemart.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.vne.skyemart.dao.GenericDAO;

@Repository
public abstract class AbstractHibernateDAO<T, ID extends Serializable> 
										implements GenericDAO< T, ID >{
	
	private Class< T > entity;
	   
	@Autowired
	SessionFactory sessionFactory;
	
	
	protected AbstractHibernateDAO(Class<T> persistentClass) {
        this.entity = persistentClass;
	}
	
	public Class<T> getPersistentClass() {
        return entity;
	}
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		return getCurrentSession().createQuery("from "+getEntityClass()).list();
	}
	
	
	@SuppressWarnings("unchecked")
	public T findById(ID id) {
		return (T) getCurrentSession().get(entity, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByProperty(String propertyName, Object value) {
		try {
			String queryString = "from " + getEntityClass() + " as model where model." + propertyName + "= :propertyVal";
			Query queryObject = getCurrentSession().createQuery(queryString);
			queryObject.setParameter("propertyVal", value);
			return queryObject.list();
		} catch (RuntimeException re) {
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(Criterion... criterion ) {
		Criteria crit = getCurrentSession().createCriteria(entity);
		for (Criterion c : criterion) {
			crit.add(c);
		}
		return crit.list();
	}
	
	@SuppressWarnings("unchecked")
	public T findObjectByCriteria(Criterion... criterion){
		Criteria crit = getCurrentSession().createCriteria(entity);
		for (Criterion c : criterion) {
			crit.add(c);
		}
		return (T) crit.uniqueResult();
	}
	
	public void save(T entity) {
		getCurrentSession().save(entity);
	}

	public void update(T entity) {
		getCurrentSession().update(entity);	
	}
	
	public void saveOrUpdate(T entity) {
		getCurrentSession().saveOrUpdate(entity);
	}
	
	public void merge(T entity) {
		getCurrentSession().merge(entity);
	}
	
	public void persist(T entity) {
		getCurrentSession().persist(entity);
	}

	public void delete(T entity) {
		getCurrentSession().delete(entity);
	}

	public void deleteById(ID entityId) {
		final T enT = findById(entityId);
		delete(enT);	
	}
	
	protected Session getCurrentSession(){
	      return sessionFactory.getCurrentSession();
	}
	
	protected String getEntityClass(){
		return entity.getName();
	}
	
	public final boolean flush() {
		try {
			getCurrentSession().flush();
			return true;
		} catch (Exception ex) {
			return false;
		}
	}
	
	public final boolean close() {
		try {
			Session session = getCurrentSession();
			if (session != null) {
				session.flush();
				session.close();
			}		
			return true;
		} catch (Exception ex) {
			return false;
		}
	}
}
